//
// Created by amon.huang on 2021/7/25.
//

#include "JNICall.h"
#include "MusicConstDefine.h"

JNICall::JNICall(JavaVM *javaVm, JNIEnv *jniEnv, jobject jPlayerObj) : jAudioInfoListener(nullptr) {
    this->javaVM = javaVm;
    this->jniEnv = jniEnv;
    this->jPlayerObj = jniEnv->NewGlobalRef(jPlayerObj);

    jclass jPlayerClazz = jniEnv->FindClass("com/amon/amonplayer/player/AmonPlayer");
    this->jPlayerErrorMid = jniEnv->GetMethodID(jPlayerClazz, "onError", "(ILjava/lang/String;)V");
    this->jPlayerPreparedMid = jniEnv->GetMethodID(jPlayerClazz, "onPrepared", "()V");
    this->jPlayerProgressMid = jniEnv->GetMethodID(jPlayerClazz, "onProgress", "()V");
    this->jPlayerCompleteMid = jniEnv->GetMethodID(jPlayerClazz, "onComplete", "()V");
    this->jVideoInfoMid = jniEnv->GetMethodID(jPlayerClazz, "onVideoInfoListener", "(II)V");
}

JNICall::~JNICall() {
    jniEnv->DeleteGlobalRef(jPlayerObj);
    if (jAudioInfoListener) {
        jniEnv->DeleteGlobalRef(jAudioInfoListener);
    }
}

void JNICall::callPlayError(ThreadMode threadMode, int code, char *msg) {
    if (threadMode == THREAD_MAIN) {
        jstring jMsg = jniEnv->NewStringUTF(msg);
        jniEnv->CallVoidMethod(jPlayerObj, jPlayerErrorMid, code, jMsg);
        jniEnv->DeleteLocalRef(jMsg);
    } else if (threadMode == THREAD_CHILD) {
        JNIEnv *env;
        if (javaVM->AttachCurrentThread(&env, 0) != JNI_OK) {
            LOGE("");
        }
        jstring jMsg = env->NewStringUTF(msg);
        env->CallVoidMethod(jPlayerObj, jPlayerErrorMid, code, jMsg);
        env->DeleteLocalRef(jMsg);
        javaVM->DetachCurrentThread();
    }
}

void JNICall::callPlayPrepared(ThreadMode threadMode) {
    if (threadMode == THREAD_MAIN) {
        jniEnv->CallVoidMethod(jPlayerObj, jPlayerPreparedMid);
    } else if (threadMode == THREAD_CHILD) {
        JNIEnv *env;
        if (javaVM->AttachCurrentThread(&env, 0) != JNI_OK) {
            LOGE("");
        }
        env->CallVoidMethod(jPlayerObj, jPlayerPreparedMid);
        javaVM->DetachCurrentThread();
    }
}

void JNICall::callPlayProgress(ThreadMode threadMode, double currentTime, double duration) const {
    if (threadMode == THREAD_MAIN) {
        jniEnv->CallVoidMethod(jPlayerObj, jPlayerProgressMid);
    } else if (threadMode == THREAD_CHILD) {
        JNIEnv *env;
        if (javaVM->AttachCurrentThread(&env, 0) != JNI_OK) {
            LOGE("");
        }
        env->CallVoidMethod(jPlayerObj, jPlayerProgressMid);
        javaVM->DetachCurrentThread();
    }
}

void JNICall::callPlayComplete(ThreadMode threadMode) const {
    if (threadMode == THREAD_MAIN) {
        jniEnv->CallVoidMethod(jPlayerObj, jPlayerCompleteMid);
    } else if (threadMode == THREAD_CHILD) {
        JNIEnv *env;
        if (javaVM->AttachCurrentThread(&env, 0) != JNI_OK) {
            LOGE("");
        }
        env->CallVoidMethod(jPlayerObj, jPlayerCompleteMid);
        javaVM->DetachCurrentThread();
    }
}

void JNICall::callVideoInfo(ThreadMode threadMode, int width, int height) const {
    if (threadMode == THREAD_MAIN) {
        jniEnv->CallVoidMethod(jPlayerObj, jVideoInfoMid, width, height);
    } else if (threadMode == THREAD_CHILD) {
        JNIEnv *env;
        if (javaVM->AttachCurrentThread(&env, 0) != JNI_OK) {
            LOGE("");
        }
        env->CallVoidMethod(jPlayerObj, jVideoInfoMid, width, height);
        javaVM->DetachCurrentThread();
    }
}

void JNICall::callMusicInfo(ThreadMode threadMode, int sampleRate, int channels) const {
    if (!jAudioInfoListener) {
        return;
    }
    if (threadMode == THREAD_MAIN) {
        jniEnv->CallVoidMethod(jAudioInfoListener, jAudioInfoMid, sampleRate, channels);
    } else if (threadMode == THREAD_CHILD) {
        JNIEnv *env;
        if (javaVM->AttachCurrentThread(&env, 0) != JNI_OK) {
            LOGE("");
        }
        env->CallVoidMethod(jAudioInfoListener, jAudioInfoMid, sampleRate, channels);
        javaVM->DetachCurrentThread();
    }
}

void JNICall::callPcmData(ThreadMode threadMode, const uint8_t *pcm, int dataSize) const {
    if (!jAudioInfoListener) {
        return;
    }
    JNIEnv *env = jniEnv;
    if (threadMode == THREAD_CHILD) {
        if (javaVM->AttachCurrentThread(&env, 0) != JNI_OK) {
            LOGE("attach current thread error");
        }
    }
    jbyte pcmByte[AUDIO_SAMPLE_RATE * 2 * 2] = {0};
    jbyteArray pcmArray = env->NewByteArray(dataSize);
    for (int i = 0; i < dataSize; ++i) {
        pcmByte[i] = *(pcm + i);
    }
    env->SetByteArrayRegion(pcmArray, 0, dataSize, pcmByte);
    env->CallVoidMethod(jAudioInfoListener, jAudioInfoPcmMid, pcmArray, dataSize);
    env->DeleteLocalRef(pcmArray);
    if (threadMode == THREAD_CHILD) {
        javaVM->DetachCurrentThread();
    }
}

void JNICall::setAudioInfoListener(jobject jListener) {
    if (!jListener) {
        return;
    }
    if (jAudioInfoListener) {
        jniEnv->DeleteGlobalRef(jAudioInfoListener);
    }
    this->jAudioInfoListener = jniEnv->NewGlobalRef(jListener);
    jclass jAudioInfoListenerClazz = jniEnv->FindClass(
            "com/amon/amonplayer/player/AudioInfoListener");
    this->jAudioInfoMid = jniEnv->GetMethodID(jAudioInfoListenerClazz, "musicInfo", "(II)V");
    this->jAudioInfoPcmMid = jniEnv->GetMethodID(jAudioInfoListenerClazz, "callbackPcm", "([BI)V");
}
